internal class ChannelNoise : PapuChannel
{
	
	
	PAPU papu;
	
	internal bool _isEnabled;
	internal bool envDecayDisable;
	internal bool envDecayLoopEnable;
	internal bool lengthCounterEnable;
	internal bool envReset;
	internal bool shiftNow;
	
	internal int lengthCounter;
	internal int progTimerCount;
	internal int progTimerMax;
	internal int envDecayRate;
	internal int envDecayCounter;
	internal int envVolume;
	internal int masterVolume;
	internal int shiftReg;
	internal int randomBit;
	internal int randomMode;
	internal int sampleValue;
	internal long accValue=0;
	internal long accCount=1;
	internal int tmp;
	
	
	internal ChannelNoise(PAPU papu){
		this.papu = papu;
		shiftReg = 1<<14;
	}
	
	internal void clockLengthCounter(){
		if(lengthCounterEnable && lengthCounter>0){
			lengthCounter--;
			if(lengthCounter == 0)updateSampleValue();
		}
	}
	
	internal void clockEnvDecay(){
		
		if(envReset){
			
			// Reset envelope:
			envReset = false;
			envDecayCounter = envDecayRate + 1;
			envVolume = 0xF;
			
		}else if(--envDecayCounter <= 0){
			
			// Normal handling:
			envDecayCounter = envDecayRate + 1;
			if(envVolume>0){
				envVolume--;
			}else{
				envVolume = envDecayLoopEnable ? 0xF : 0;
			}
			
		}
		
		masterVolume = envDecayDisable ? envDecayRate : envVolume;
		updateSampleValue();

	}
	
	internal void updateSampleValue(){
		if(_isEnabled && lengthCounter>0){
			sampleValue = randomBit * masterVolume;
		}
	}
	
	internal override void writeReg(int address, int value){
		
		if(address == 0x400C){
			
			// Volume/Envelope decay:
			envDecayDisable = ((value&0x10)!=0);
			envDecayRate = value&0xF;
			envDecayLoopEnable = ((value&0x20)!=0);
			lengthCounterEnable = ((value&0x20)==0);
			masterVolume = envDecayDisable?envDecayRate:envVolume;
			
		}else if(address == 0x400E){
			
			// Programmable timer:
			progTimerMax = papu.getNoiseWaveLength(value&0xF);
			randomMode = value>>7;
			
		}else if(address == 0x400F){
			
			// Length counter
			lengthCounter = papu.getLengthMax(value&248);
			envReset = true;
			
		}
		
		// Update:
		//updateSampleValue();
		
	}
	
	internal override void setEnabled(bool value){
		
		_isEnabled = value;
		if(!value)lengthCounter = 0;
		updateSampleValue();
		
	}
	
	internal override bool isEnabled(){
		return _isEnabled;
	}
	
	internal override int getLengthStatus(){
		return ((lengthCounter==0 || !_isEnabled)?0:1);
	}
	
	internal override void reset(){
		
		progTimerCount = 0;
		progTimerMax = 0;
		_isEnabled = false;
		lengthCounter = 0;
		lengthCounterEnable = false;
		envDecayDisable = false;
		envDecayLoopEnable = false;
		shiftNow = false;
		envDecayRate = 0;
		envDecayCounter = 0;
		envVolume = 0;
		masterVolume = 0;
		shiftReg = 1;
		randomBit = 0;
		randomMode = 0;
		sampleValue = 0;
		tmp = 0;
		
	}
	
	internal void destroy(){
		papu = null;
	}
	
}